package com.hey.snmp.test;

import com.hey.mib.entity.BaseInterface;
import com.hey.mib.entity.OphylinkGenCardS10ConfEntry;
import com.hey.mib.proxy.util.ProxyUtil;
import com.hey.snmp.test.entity.PduTarget;
import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.TransportMapping;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.event.ResponseListener;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.*;
import org.snmp4j.transport.DefaultUdpTransportMapping;

import java.io.IOException;
import java.util.*;

/**
 * @说明 SNMP4J测试
 * @author cuisuqiang
 * @version 1.0
 * @since
 */
public class SnmpUtil {
	private Snmp snmp = null;
	private Address targetAddress = null;

	public void initComm() throws IOException {
		// 设置Agent方的IP和端口
		targetAddress = GenericAddress.parse("udp:10.0.0.113/161");
		TransportMapping transport = new DefaultUdpTransportMapping();
		snmp = new Snmp(transport);
		transport.listen();
	}

	/**
	 * 发送同步消息
	 * @param pdu
	 * @return
	 * @throws IOException
	 */
	public ResponseEvent sendPDUSync(PDU pdu) throws IOException {
		// 设置 目标
		CommunityTarget target = new CommunityTarget();
		target.setCommunity(new OctetString("dev123"));
		target.setAddress(targetAddress);
		// 通信不成功时的重试次数 N+1次
		target.setRetries(2);
		// 超时时间
		target.setTimeout(2 * 1000);
		// SNMP 版本
		target.setVersion(SnmpConstants.version2c);
		// 向Agent发送PDU，并返回Response
		return snmp.send(pdu, target);
	}


	/**
	 * 发送异步消息
	 * @param pdu
	 * @return
	 * @throws IOException
	 */
	public ResponseEvent sendPDUAsync(PDU pdu) throws IOException {
		// 设置 目标
		CommunityTarget target = new CommunityTarget();
		target.setCommunity(new OctetString("public"));
		target.setAddress(targetAddress);
		// 通信不成功时的重试次数 N+1次
		target.setRetries(2);
		// 超时时间
		target.setTimeout(2 * 1000);
		// SNMP 版本
		target.setVersion(SnmpConstants.version2c);

		// 设置监听对象
		ResponseListener listener = new ResponseListener() {
			public void onResponse(ResponseEvent event) {
				System.out.println("---------->开始异步解析<------------");
				readResponse(event);
			}
		};
		// 发送报文
		snmp.send(pdu, target, null, listener);
		return null;
	}

	/**
	 * 获取单个oid的response
	 * @param oid
	 * @throws IOException
	 */
	public void getPDUSingle(String oid) throws IOException {
		// PDU 对象
		PDU pdu = new PDU();
		pdu.add(new VariableBinding(new OID(oid)));
		// 操作类型
//		pdu.setType(PDU.GET);
		pdu.setType(PDU.GETNEXT);
		ResponseEvent revent = sendPDUSync(pdu);
		if(null != revent){
			readResponse(revent);
		}
	}

	/**
	 * 设置单个oid
	 * @throws IOException
	 */
	public void setSinglePDU(PduTarget target) throws IOException {
		// set PDU
//		PDU pdu = new PDU();
//		if (target.getIntMessage()!=null){
//			pdu.add(new VariableBinding(new OID(target.getOid()), new Integer32(target.getIntMessage())));
//		}else {
//			pdu.add(new VariableBinding(new OID(target.getOid()), new OctetString(target.getStringMessage())));
//		}
//		pdu.setType(PDU.SET);
//		ResponseEvent EVENT = sendPDUSync(pdu);
	}

	/**
	 * 批量设置oid
	 * @throws IOException
	 */
	public void setPDUBatch(List<PduTarget> targetList) throws IOException {
		// set PDU batch
		PDU pdu = new PDU();
		long begin = System.currentTimeMillis();
		if(targetList!=null && targetList.size()>0) {
			targetList.forEach(pduTarget -> {
				if (pduTarget.getGauge32Message() != null) {
					//是int类型的数据
					pdu.add(new VariableBinding(new OID(pduTarget.getOid()),pduTarget.getGauge32Message()));
				} else if(pduTarget.getInteger32Message() != null){
					pdu.add(new VariableBinding(new OID(pduTarget.getOid()),pduTarget.getInteger32Message()));
				}else if(pduTarget.getIpAddressMessage() != null){
					pdu.add(new VariableBinding(new OID(pduTarget.getOid()),pduTarget.getIpAddressMessage()));
				}else if(pduTarget.getOctetStringMessage() != null){
					pdu.add(new VariableBinding(new OID(pduTarget.getOid()),pduTarget.getOctetStringMessage()));
				}
			});

		}
		pdu.setType(PDU.SET);
		ResponseEvent event = sendPDUSync(pdu);
		System.out.println(System.currentTimeMillis()-begin);
	}

	/**
	 * 解析response
	 * @param respEvent
	 */
	public void readResponse(ResponseEvent respEvent) {
		// 解析Response
		System.out.println("------------>解析Response<-------------");
		if (respEvent != null && respEvent.getResponse() != null) {
			Vector<VariableBinding> recVBs = respEvent.getResponse()
					.getVariableBindings();
			for (int i = 0; i < recVBs.size(); i++) {
				VariableBinding recVB = recVBs.elementAt(i);
				System.out.println(recVB.getOid() + " : "
						+ recVB.getVariable().toString());
			}
		}
	}

	/**
	 * 将实体类转为PduTarget
	 * @param baseInterface
	 */
	public List<PduTarget> buildPDUTarget(BaseInterface baseInterface,List<String> attributes){
		ProxyUtil proxyUtil = new ProxyUtil(baseInterface);
		String oid = proxyUtil.getOIDMapping();
		Map attributeOids = proxyUtil.getIndexMap();
		Map values = proxyUtil.getValues();
		List<PduTarget> tempList = new ArrayList<>();
		String property;
		for (int i=0;i<attributes.size();i++) {
			String tableIndexOID = proxyUtil.getTableIndexOID();
			property = attributes.get(i);
			if(values.get(property) instanceof Integer32){
				//Integer32类型
				tempList.add(new PduTarget(oid + "." + attributeOids.get(property)+"."+tableIndexOID, (Integer32) values.get(property)));
			}else if(values.get(property) instanceof OctetString){
				//字符串类型
				tempList.add(new PduTarget(oid + "." + attributeOids.get(property)+"."+tableIndexOID, (OctetString)values.get(property)));
			}else if(values.get(property) instanceof Gauge32){
				//Gauge32类型
				tempList.add(new PduTarget(oid + "." + attributeOids.get(property)+"."+tableIndexOID, (Gauge32)values.get(property)));
			}else if(values.get(property) instanceof IpAddress){
				//ip地址类型
				tempList.add(new PduTarget(oid + "." + attributeOids.get(property)+"."+tableIndexOID, (IpAddress)values.get(property)));
			}
		}
		return tempList;
	}

	public static void main(String[] args) {
		try {
			System.out.println(new Date());
			long begin = System.currentTimeMillis();
			SnmpUtil util = new SnmpUtil();
			util.initComm();
			OphylinkGenCardS10ConfEntry confEntry = new OphylinkGenCardS10ConfEntry();
			confEntry.setTableIndexOID("6");
			confEntry.setGcscAllModuleTxCtrl(new Gauge32(1));
			confEntry.setGcscAllPortAls(new Gauge32(1));
			List list = new ArrayList();
			list.add("gcscAllModuleTxCtrl");

			List<PduTarget> targetList = util.buildPDUTarget(confEntry,list);
			//设置批量oid的值
			util.setPDUBatch(targetList);
			System.out.println(System.currentTimeMillis()-begin);

		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}